#include <BString.h>
#include <stdio.h>

using namespace blueberry;
BString::BString()
{
	z_Data = new char[B_INIT_STRING_SIZE];//Pre-allocates memory for future data copy
	ui_Len = 0;
	ui_AllocatedLen = B_INIT_STRING_SIZE;
}


BString::BString(BString & _rSrc)
{
	ui_Len = _rSrc.ui_Len;
	z_Data = new char[ui_Len + 1];
	memcpy(z_Data, _rSrc.z_Data, ui_Len + 1);//Assuming source string has a null charector at the end
	ui_AllocatedLen = ui_Len + 1;
}

BString::BString(const char *_zData)
{
	ui_Len = strlen(_zData);//Assuming source string has a null charector at the end
	z_Data = new char[ui_Len + 1];
	memcpy(z_Data, _zData, ui_Len + 1);//Should be safer since above assumption prevails
	ui_AllocatedLen = ui_Len + 1;
}

BString::BString(const char * _zBuffer, UInt _uiLen)
{
	ui_Len = _uiLen;
	z_Data = new char[ui_Len + 1];
	memcpy(z_Data, _zBuffer, ui_Len);
	z_Data[ui_Len] = 0;
	ui_AllocatedLen = ui_Len + 1;
}

BString::BString(string & _sSrc)
{
	ui_Len = _sSrc.size();
	z_Data = new char[ui_Len + 1];
	memcpy(z_Data, _sSrc.c_str(), ui_Len + 1);//Assuming std string also uses null charector at the end
	ui_AllocatedLen = ui_Len + 1;
}

BString::~BString()
{
	delete[] z_Data;
	z_Data = NULL;
	ui_Len = 0;
	ui_AllocatedLen = 0;
}

void BString::append(const char * _zData)
{
	UInt uiSize = strlen(_zData);
	resize(uiSize);
	memcpy(z_Data + ui_Len, _zData, uiSize + 1);//Assuming source string is null terminated
	ui_Len += uiSize;
}
void BString::append(BString & _rSrc)
{
	UInt uiSize = _rSrc.ui_Len;
	resize(uiSize);
	memcpy(z_Data + ui_Len, _rSrc.z_Data, uiSize + 1);//Assuming source string is null terminated
	ui_Len += uiSize;
}
void BString::append(string & _rSrc)
{
	UInt uiSize = _rSrc.size();
	resize(uiSize);
	memcpy(z_Data + ui_Len, _rSrc.c_str(), uiSize + 1);//Assuming source string is null terminated
	ui_Len += uiSize;
}

void BString::operator+=(BString & _rSrc)
{
	UInt uiSize = _rSrc.ui_Len;
	resize(uiSize);
	memcpy(z_Data + ui_Len, _rSrc.z_Data, uiSize + 1);//Assuming source string is null terminated
	ui_Len += uiSize;
}
void BString::operator+=(string & _rSrc)
{
	UInt uiSize = _rSrc.size();
	resize(uiSize);
	memcpy(z_Data + ui_Len, _rSrc.c_str(), uiSize + 1);//Assuming source string is null terminated
	ui_Len += uiSize;
}

void BString::operator+=(const char * _zData)
{
	UInt uiSize = strlen(_zData);
	resize(uiSize);
	memcpy(z_Data + ui_Len, _zData, uiSize + 1);//Assuming source string is null terminated
	ui_Len += uiSize;
}

void BString::operator +=(char _cValue)
{
	UInt uiSize = 1;
	resize(uiSize);
	z_Data[ui_Len] = _cValue;
	ui_Len += uiSize;
}

void BString::operator +=(float _fValue)
{
	char zTemp[100];
	UInt uiSize = sprintf(zTemp, "%f", _fValue);
	resize(uiSize);
	memcpy(z_Data + ui_Len, zTemp, uiSize + 1);
	ui_Len += uiSize;
}

void BString::operator +=(double _dValue)
{
	char zTemp[100];
	UInt uiSize = sprintf(zTemp, "%f", _dValue);
	resize(uiSize);
	memcpy(z_Data + ui_Len, zTemp, uiSize + 1);
	ui_Len += uiSize;
}

void BString::operator +=(Byte _btValue)
{
	UInt uiSize = 1;
	resize(uiSize);
	z_Data[ui_Len] = _btValue;
	ui_Len += uiSize;
}

void BString::operator +=(UInt _uiValue)
{
	char zTemp[100];
	UInt uiSize = sprintf(zTemp, "%u", _uiValue);
	resize(uiSize);
	memcpy(z_Data + ui_Len, zTemp, uiSize + 1);
	ui_Len += uiSize;
}

void BString::operator +=(int _iValue)
{
	char zTemp[100];
	UInt uiSize = sprintf(zTemp, "%d", _iValue);
	resize(uiSize);
	memcpy(z_Data + ui_Len, zTemp, uiSize + 1);
	ui_Len += uiSize;
}

void BString::resize(UInt _uiSize)
{
	UInt uiNewLen = ui_Len + _uiSize + 1;
	if (uiNewLen <= ui_AllocatedLen)
	{
		return;
	}
	ui_AllocatedLen = uiNewLen + B_STRING_EXPANSION_SIZE;
	char * zNewData = new char[ui_AllocatedLen];
	memcpy(zNewData, z_Data, ui_Len);
	delete z_Data;
	z_Data = zNewData;
}

void BString::trim()
{
	trim(' ');
}

void BString::trim(char _cDelim)
{
	for (UInt ui = ui_Len - 1; ui >= 0; --ui)
	{
		char c = z_Data[ui];
		if ( c == _cDelim)
		{
			continue;
		}
		else
		{
			ui_Len = ui + 1;
			z_Data[ui_Len] = 0;
			UInt uiPos = 0;
			for (UInt uj = 0; uj < ui_Len ; ++uj)
			{
				char d = z_Data[uj];
				if ( d == _cDelim)
				{
					++uiPos;
					continue;
				}
				else
				{
					if ( uiPos > 0 )
					{
						memmove(z_Data, z_Data + uiPos, ui_Len - uiPos);
						ui_Len -= uiPos;
						z_Data[ui_Len] = 0;
						return;
					}
				}
			}
			return;
		}
	}
}
BStringTokenList* BString::tokenize(char _cDelim)
{
	UInt uiPos = 0;
	BStringTokenList * pTokList = new BStringTokenList();
	for ( UInt ui = 0; ui < ui_Len; ++ui)
	{
		if ( z_Data[ui] == _cDelim)
		{
			BString * pTok = new BString(z_Data + uiPos, ui - uiPos);
			pTokList->vec_Tokens.push_back(pTok);
			uiPos = ui + 1;
		}
	}
	BString * pTok = new BString(z_Data + uiPos, ui_Len - uiPos);
	pTokList->vec_Tokens.push_back(pTok);
	pTokList->ite = pTokList->vec_Tokens.begin();
	return pTokList;
}

BStringTokenList::~BStringTokenList()
{
	for ( BSTRING_VECTOR::iterator ite = vec_Tokens.begin(); ite < vec_Tokens.end(); ++ite)
	{
		BString * pTok = *ite;
		delete pTok;
	}
	vec_Tokens.clear();
}

BString * BStringTokenList::getNextToken()
{
	if ( ite == vec_Tokens.end())
		return NULL;

	BString * pTok = *ite;
	++ite;
	return pTok;
}

int BString::find(const char * _zStr)
{
	UInt uiSize = strlen(_zStr);
	for ( UInt ui = 0; ui < ui_Len; ++ui )
	{
		if ( strncmp(z_Data + ui, _zStr, uiSize) == 0 )
		{
			return ui;
		}
	}
	return -1;
}
